package org.lhh.server.core.codec.steps;

import com.mxgraph.model.mxCell;
import com.mxgraph.util.mxDomUtils;
import org.apache.commons.lang3.StringUtils;
import org.lhh.server.common.utils.CollectionUtils;
import org.lhh.server.common.utils.JsonUtils;
import org.pentaho.di.cluster.ClusterSchema;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.exception.KettlePluginException;
import org.pentaho.di.core.plugins.PluginInterface;
import org.pentaho.di.core.plugins.PluginRegistry;
import org.pentaho.di.core.plugins.StepPluginType;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.StepErrorMeta;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaInterface;
import org.pentaho.di.trans.step.StepPartitioningMeta;
import org.pentaho.metastore.api.IMetaStore;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.util.List;
import java.util.Map;


public abstract class AbstractStep implements StepEncoder {

    @Override
    public StepMeta decodeStep(TransMeta transMeta, mxCell cell, List<DatabaseMeta> databases, IMetaStore metaStore){
        String stepName = cell.getAttribute("label");
        String stepId = cell.getAttribute("pluginId");
        PluginRegistry registry = PluginRegistry.getInstance();
        PluginInterface pluginInterface = registry.findPluginWithId(StepPluginType.class, stepId);
        try {
            StepMetaInterface stepMetaInterface  = (StepMetaInterface) registry.loadClass(pluginInterface);
            if (stepMetaInterface != null) {
                StepMeta stepMeta = new StepMeta(stepId, stepName, decode(transMeta,stepMetaInterface, cell, databases, metaStore));
                stepMeta.setDescription(cell.getAttribute("description"));
                String distribute = cell.getAttribute( "distribute" );
                if ( distribute == null ) {
                    stepMeta.setDistributes(true);
                } else {
                    stepMeta.setDistributes("Y".equalsIgnoreCase( distribute ));
                }
                String partitioning = cell.getAttribute("partitioning");
                StepPartitioningMeta stepPartitioningMeta = StepPartitioningMetaCodec.decode(JsonUtils.jsonToBean(partitioning, Map.class));
                stepMeta.setStepPartitioningMeta(stepPartitioningMeta);
                stepMeta.setCopiesString(cell.getAttribute("copies"));
                String cluster_schema = cell.getAttribute("cluster_schema");
                if (StringUtils.isNotEmpty(cluster_schema)) {
                    stepMeta.setClusterSchemaName(cluster_schema);
                    List<ClusterSchema> clusterSchemas = transMeta.getClusterSchemas();
                    if (!CollectionUtils.isEmpty(clusterSchemas)) {
                        for (ClusterSchema clusterSchema : clusterSchemas) {
                            if (cluster_schema.equals(clusterSchema.getName())) {
                                stepMeta.setClusterSchema(clusterSchema);
                            }
                        }
                    }
                }
                stepMeta.setLocation((int) cell.getGeometry().getX(), (int) cell.getGeometry().getY());
                String error = cell.getAttribute("error");
                if (StringUtils.isNotEmpty(error)) {
                    StepErrorMeta stepErrorMeta = StepErrorMetaCodec.decode(transMeta, JsonUtils.jsonToBean(error, Map.class));
                    stepMeta.setStepErrorMeta(stepErrorMeta);
                }
                return stepMeta;
            }
        } catch (KettlePluginException ignored) {

        }
        return null;
    }

    @Override
    public Element encodeStep(StepMeta stepMeta){
        Document doc = mxDomUtils.createDocument();
        Element e = doc.createElement("Step");
        encode(e, stepMeta.getStepMetaInterface());
        e.setAttribute("label", stepMeta.getName());
        e.setAttribute("pluginId", stepMeta.getTypeId());
        e.setAttribute("description", stepMeta.getDescription() == null ? "" : stepMeta.getDescription());
        e.setAttribute("distribute", stepMeta.isDistributes() ? "Y" : "N");
        StepPartitioningMeta stepPartitioningMeta = stepMeta.getStepPartitioningMeta();
        e.setAttribute("partitioning", JsonUtils.beanToJson(StepPartitioningMetaCodec.encode(stepPartitioningMeta)));
        if (stepMeta.isPartitioned())
            e.setAttribute("copies", "1");
        else
            e.setAttribute("copies", String.valueOf(stepMeta.getCopies()));
        ClusterSchema clusterSchema = stepMeta.getClusterSchema();
        if (clusterSchema != null)
            e.setAttribute("cluster_schema", clusterSchema.getName());
        if (stepMeta.getStepErrorMeta() != null)
            e.setAttribute("error", StepErrorMetaCodec.encode(stepMeta.getStepErrorMeta()).toString());
        e.setAttribute("supports_error_handing", stepMeta.supportsErrorHandling() ? "Y" : "N");
        return e;
    }

    public abstract StepMetaInterface decode(TransMeta transMeta,StepMetaInterface stepMetaInterface, mxCell cell, List<DatabaseMeta> databases, IMetaStore metaStore);

    public abstract void encode(Element e, StepMetaInterface stepMetaInterface);

}
